#!/usr/bin/env python3
"""
代码沙箱服务综合测试运行器
支持选择性运行不同类型的测试用例
"""

import asyncio
import argparse
import sys
import os
import time
from datetime import datetime
from typing import Dict, List, Any, Optional

# 添加测试目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from base_test import BaseCodeSandboxTest
from test_python_executor import TestPythonExecutor
from test_javascript_executor import TestJavaScriptExecutor
from test_bash_executor import TestBashExecutor
from verify_security_hardening import SecurityHardeningVerifier


class TestRunner:
    """测试运行器"""
    
    def __init__(self, base_url: str = "http://localhost:8003"):
        self.base_url = base_url
        self.all_results: List[Dict[str, Any]] = []
        self.start_time: Optional[float] = None
        self.end_time: Optional[float] = None

    async def check_service_availability(self) -> bool:
        """检查服务可用性"""
        print("🔍 检查服务可用性...")
        
        async with BaseCodeSandboxTest(self.base_url) as base_tester:
            if not await base_tester.check_service_health():
                print("❌ 服务不可用，请先启动代码沙箱服务")
                print("   启动命令: python3 start_service.py")
                return False
            
            # 测试基本API接口
            await base_tester.test_service_status()
            print("✅ 服务可用性检查通过")
            return True
    
    async def run_bash_tests(self) -> Dict[str, Any]:
        """运行Bash测试"""
        print("\n" + "="*60)
        print("💻 开始Bash代码执行器测试")
        print("="*60)
        
        start_time = time.time()
        tester = TestBashExecutor()
        tester.base_url = self.base_url
        
        async with tester:
            success = await tester.run_all_tests()
            tester.print_test_summary()
        
        end_time = time.time()
        
        return {
            "test_type": "Bash",
            "success": success,
            "duration": end_time - start_time,
            "total_tests": len(tester.test_results),
            "passed_tests": sum(1 for r in tester.test_results if r["success"]),
            "results": tester.test_results
        }
    
    async def run_security_tests(self) -> Dict[str, Any]:
        """运行安全加固测试"""
        print("\n" + "="*60)
        print("🔒 开始安全加固验证测试")
        print("="*60)
        
        start_time = time.time()
        verifier = SecurityHardeningVerifier(self.base_url)
        
        try:
            await verifier.setup()
            await verifier.run_all_security_tests()
            
            # 生成详细的安全报告
            verifier.generate_security_report()
            
            # 计算测试结果统计
            total_tests = len(verifier.test_results)
            successful_tests = sum(1 for r in verifier.test_results if r.get("success", False))
            
            # 分类统计恶意代码和正常代码测试
            malicious_tests = [r for r in verifier.test_results if r.get("expected_blocked", False)]
            normal_tests = [r for r in verifier.test_results if not r.get("expected_blocked", False)]
            
            blocked_malicious = sum(1 for r in malicious_tests if r.get("blocked", False))
            allowed_normal = sum(1 for r in normal_tests if not r.get("blocked", False))
            
            # 计算成功标准：90%以上的恶意代码被阻止，且90%以上的正常代码正常执行
            malicious_block_rate = blocked_malicious / len(malicious_tests) if malicious_tests else 1.0
            normal_pass_rate = allowed_normal / len(normal_tests) if normal_tests else 1.0
            
            success = malicious_block_rate >= 0.9 and normal_pass_rate >= 0.9
            
        except Exception as e:
            print(f"❌ 安全测试执行失败: {e}")
            success = False
            total_tests = 0
            successful_tests = 0
            verifier.test_results = []
        finally:
            await verifier.cleanup()
        
        end_time = time.time()
        
        return {
            "test_type": "Security",
            "success": success,
            "duration": end_time - start_time,
            "total_tests": total_tests,
            "passed_tests": successful_tests,
            "results": verifier.test_results
        }

    async def run_python_tests(self) -> Dict[str, Any]:
        """运行Python测试"""
        print("\n" + "="*60)
        print("🐍 开始Python代码执行器测试")
        print("="*60)
        
        start_time = time.time()
        tester = TestPythonExecutor()
        tester.base_url = self.base_url
        
        async with tester:
            success = await tester.run_all_tests()
            tester.print_test_summary()
        
        end_time = time.time()
        
        return {
            "test_type": "Python",
            "success": success,
            "duration": end_time - start_time,
            "total_tests": len(tester.test_results),
            "passed_tests": sum(1 for r in tester.test_results if r["success"]),
            "results": tester.test_results
        }
    
    async def run_javascript_tests(self) -> Dict[str, Any]:
        """运行JavaScript测试"""
        print("\n" + "="*60)
        print("🟨 开始JavaScript代码执行器测试")
        print("="*60)
        
        start_time = time.time()
        tester = TestJavaScriptExecutor()
        tester.base_url = self.base_url
        
        async with tester:
            success = await tester.run_all_tests()
            tester.print_test_summary()
        
        end_time = time.time()
        
        return {
            "test_type": "JavaScript",
            "success": success,
            "duration": end_time - start_time,
            "total_tests": len(tester.test_results),
            "passed_tests": sum(1 for r in tester.test_results if r["success"]),
            "results": tester.test_results
        }
    
    async def run_performance_tests(self) -> Dict[str, Any]:
        """运行性能测试"""
        print("\n" + "="*60)
        print("⚡ 开始性能压力测试")
        print("="*60)
        
        start_time = time.time()
        
        # 创建性能测试用例
        performance_cases = [
            {
                "name": "并发Python任务",
                "code": "import time\nprint('Task started')\ntime.sleep(1)\nprint('Task completed')",
                "concurrent_count": 10,
                "code_type": "python"
            },
            {
                "name": "并发JavaScript任务", 
                "code": "console.log('Task started');\nfor(let i = 0; i < 1000000; i++) { /* 模拟计算 */ }\nconsole.log('Task completed');",
                "concurrent_count": 8,
                "code_type": "javascript"
            }
        ]
        
        results = []
        
        for case in performance_cases:
            print(f"📊 测试: {case['name']} (并发数: {case['concurrent_count']})")
            
            case_start = time.time()
            
            # 创建测试器
            tester = BaseCodeSandboxTest(self.base_url)
            tester.code_type = case["code_type"]
            
            async with tester:
                # 并发提交任务
                tasks = []
                for i in range(case["concurrent_count"]):
                    task_id = await tester.submit_task(
                        code=case["code"],
                        security_level="low",
                        timeout_seconds=10
                    )
                    tasks.append(tester.wait_for_completion(task_id, 15))
                
                # 等待所有任务完成
                try:
                    task_results = await asyncio.gather(*tasks, return_exceptions=True)
                    
                    successful_tasks = sum(1 for r in task_results 
                                         if isinstance(r, dict) and r.get("status") == "completed")
                    
                    case_end = time.time()
                    case_duration = case_end - case_start
                    
                    print(f"  ✅ 完成: {successful_tasks}/{case['concurrent_count']} 任务成功")
                    print(f"  ⏱️  用时: {case_duration:.2f}秒")
                    print(f"  📈 吞吐量: {successful_tasks/case_duration:.2f} 任务/秒")
                    
                    results.append({
                        "name": case["name"],
                        "concurrent_count": case["concurrent_count"],
                        "successful_tasks": successful_tasks,
                        "duration": case_duration,
                        "throughput": successful_tasks / case_duration if case_duration > 0 else 0
                    })
                    
                except Exception as e:
                    print(f"  ❌ 性能测试失败: {e}")
                    results.append({
                        "name": case["name"],
                        "error": str(e)
                    })
        
        end_time = time.time()
        
        return {
            "test_type": "Performance",
            "success": len(results) > 0,
            "duration": end_time - start_time,
            "total_tests": len(performance_cases),
            "passed_tests": len([r for r in results if "error" not in r]),
            "results": results
        }
    
    async def run_selected_tests(self, test_types: List[str]) -> List[Dict[str, Any]]:
        """运行选定的测试类型"""
        results = []
        
        test_map = {
            "bash": self.run_bash_tests,
            "python": self.run_python_tests,
            "javascript": self.run_javascript_tests,
            "security": self.run_security_tests,
            "performance": self.run_performance_tests,
        }
        
        for test_type in test_types:
            if test_type.lower() in test_map:
                try:
                    result = await test_map[test_type.lower()]()
                    results.append(result)
                except Exception as e:
                    print(f"❌ {test_type} 测试执行失败: {e}")
                    results.append({
                        "test_type": test_type,
                        "success": False,
                        "error": str(e),
                        "duration": 0,
                        "total_tests": 0,
                        "passed_tests": 0
                    })
            else:
                print(f"⚠️ 未知的测试类型: {test_type}")
        
        return results
    
    def print_comprehensive_report(self, results: List[Dict[str, Any]]):
        """打印综合测试报告"""
        print("\n" + "="*80)
        print("📋 代码沙箱服务综合测试报告")
        print("="*80)
        
        # 基本统计
        total_test_suites = len(results)
        successful_suites = sum(1 for r in results if r.get("success", False))
        total_duration = sum(r.get("duration", 0) for r in results)
        total_tests = sum(r.get("total_tests", 0) for r in results)
        total_passed = sum(r.get("passed_tests", 0) for r in results)
        
        print(f"\n📊 总体统计:")
        print(f"  测试套件数量: {total_test_suites}")
        print(f"  成功套件数量: {successful_suites}")
        print(f"  总测试用例数: {total_tests}")
        print(f"  通过测试数量: {total_passed}")
        print(f"  总体成功率: {(total_passed/total_tests*100):.1f}%" if total_tests > 0 else "  总体成功率: 0%")
        print(f"  总执行时间: {total_duration:.2f}秒")
        
        # 各测试套件详情
        print(f"\n📝 测试套件详情:")
        for result in results:
            test_type = result.get("test_type", "Unknown")
            success = result.get("success", False)
            duration = result.get("duration", 0)
            total = result.get("total_tests", 0)
            passed = result.get("passed_tests", 0)
            
            status_icon = "✅" if success else "❌"
            print(f"  {status_icon} {test_type}:")
            print(f"    状态: {'通过' if success else '失败'}")
            print(f"    用例: {passed}/{total} 通过")
            print(f"    用时: {duration:.2f}秒")
            
            if "error" in result:
                print(f"    错误: {result['error']}")
        
        # 性能数据
        perf_result = next((r for r in results if r.get("test_type") == "Performance"), None)
        if perf_result and "results" in perf_result:
            print(f"\n⚡ 性能测试结果:")
            for perf_case in perf_result["results"]:
                if "error" not in perf_case:
                    print(f"  📈 {perf_case['name']}:")
                    print(f"    并发数: {perf_case['concurrent_count']}")
                    print(f"    成功率: {perf_case['successful_tasks']}/{perf_case['concurrent_count']}")
                    print(f"    吞吐量: {perf_case['throughput']:.2f} 任务/秒")
        
        # 安全评估
        security_result = next((r for r in results if r.get("test_type") == "Security"), None)
        if security_result:
            blocked_rate = (security_result.get("passed_tests", 0) / 
                          security_result.get("total_tests", 1) * 100)
            
            print(f"\n🛡️ 安全评估:")
            if blocked_rate >= 95:
                print(f"  🟢 安全等级: 优秀 ({blocked_rate:.1f}% 攻击被阻止)")
            elif blocked_rate >= 85:
                print(f"  🟡 安全等级: 良好 ({blocked_rate:.1f}% 攻击被阻止)")
            elif blocked_rate >= 70:
                print(f"  🟠 安全等级: 中等 ({blocked_rate:.1f}% 攻击被阻止)")
            else:
                print(f"  🔴 安全等级: 危险 ({blocked_rate:.1f}% 攻击被阻止)")
        
        # 建议和总结
        print(f"\n💡 建议:")
        if successful_suites == total_test_suites:
            print("  🎉 所有测试套件都通过了！代码沙箱服务运行正常。")
        else:
            failed_suites = [r["test_type"] for r in results if not r.get("success", False)]
            print(f"  ⚠️ 以下测试套件需要关注: {', '.join(failed_suites)}")
            print("  🔧 建议检查日志并修复相关问题。")
        
        if total_passed / total_tests < 0.9 if total_tests > 0 else False:
            print("  📈 考虑增强错误处理和安全机制。")
        
        print(f"\n⏰ 测试完成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")

async def main():
    """主函数"""
    parser = argparse.ArgumentParser(description="代码沙箱服务综合测试工具")
    parser.add_argument("--url", default="http://localhost:8000", 
                       help="服务地址 (默认: http://localhost:8000)")
    parser.add_argument("--tests", nargs="+", 
                       choices=["bash", "python", "javascript", "security", "performance", "all"],
                       default=["all"],
                       help="要运行的测试类型")
    parser.add_argument("--no-service-check", action="store_true",
                       help="跳过服务可用性检查")
    
    args = parser.parse_args()
    
    print("🚀 代码沙箱服务综合测试工具")
    print(f"📍 目标服务: {args.url}")
    print(f"🎯 测试类型: {args.tests}")
    print("-" * 60)
    
    runner = TestRunner(args.url)
    runner.start_time = time.time()
    
    try:
        # 检查服务可用性
        if not args.no_service_check:
            if not await runner.check_service_availability():
                return False
        
        # 确定要运行的测试类型
        if "all" in args.tests:
            test_types = ["bash", "python", "javascript", "security", "performance"]
        else:
            test_types = args.tests
        
        # 运行测试
        results = await runner.run_selected_tests(test_types)
        runner.all_results = results
        
        # 打印综合报告
        runner.end_time = time.time()
        runner.print_comprehensive_report(results)
        
        # 返回总体成功状态
        return all(r.get("success", False) for r in results)
        
    except KeyboardInterrupt:
        print("\n\n❌ 测试被用户中断")
        return False
    except Exception as e:
        print(f"\n\n❌ 测试执行失败: {e}")
        import traceback
        traceback.print_exc()
        return False

if __name__ == "__main__":
    success = asyncio.run(main())
    exit(0 if success else 1) 
